#include <errno.h>
#include <fcntl.h>

#include <linux/sched.h>
#include <asm/segment.h>

#define MIN(a, b) (((a) < (b)) ? (a) : (b))

int file_read(struct m_inode *inode, struct file *filp, char *buf, int count)
{
    int left, chars, nr;
    struct buffer_head *bh;

    left = count;
    if (left <= 0) {
        return 0;
    }
    while (left) {
        nr = bmap(inode, (filp->f_pos) / BLOCK_SIZE);
        if (nr) {
            bh = bread(inode->i_dev, nr);
            if (!bh)
                break;
        }
        else
            bh = NULL;
        
        nr = filp->f_pos % BLOCK_SIZE;
        chars = MIN(BLOCK_SIZE - nr, left);
        filp->f_pos += chars;
        left -= chars;
        
        if (bh) {
            char *p = nr + bh->b_data;
            while (chars-- > 0)
                put_fs_byte(*(p++), buf++);
            brelse(bh);
        } else {
            while (chars-- > 0)
                put_fs_byte(0, buf++);
        }
    }
    inode->i_atime = CURRENT_TIME;
    return (count - left) ? (count - left) : -ERROR;
}

int file_write(struct m_inode *inode, struct file *filp, char *buf, int count)
{
    off_t pos;
    int block, c;
    struct buffer_head *bh;
    char *p;
    int i = 0;

    if (filp->f_flags & O_APPEND)   // 在文件末尾添加
        pos = inode->i_size;
    else                            // 从当前的位置更改
        pos = filp->f_pos;
    while (i < count) {
        // 找到文件读写指针所在的逻辑块
        block = create_block(inode, pos / BLOCK_SIZE);
        if (!block)
            break;
        bh = bread(inode->i_dev, block);
        if (!bh)
            break;
        c = pos % BLOCK_SIZE;   // 文件读写指针在逻辑块中的偏移
        p = c + bh->b_data;     // 文件读写指针在文件缓冲区的偏移
        bh->b_dirt = 1;
        c = BLOCK_SIZE - c;
        if (c > count - i)
            c = count - i;      // 计算要向该逻辑块写入的字符个数
        pos += c;
        if (pos > inode->i_size) {
            inode->i_size = pos;
            inode->i_dirt = 1;
        }
        i += c;
        while (c-- > 0)         // 复制数据
            *(p++) = get_fs_byte(buf++);
        brelse(bh);
    }
    inode->i_mtime = CURRENT_TIME;
    if (!(filp->f_flags & O_APPEND)) {
        filp->f_pos = pos;
        inode->i_ctime = CURRENT_TIME;
    }
    return (i ? i : -1);
}
